/*
 * dcmi.c
 *
 *  Created on: 2017年7月11日
 *      Author: changruowang
 */
#include "user_bsp.h"
#include "system.h"


volatile uint8_t Ov7725_vsync = 0;          //flag of FIFO can be read

#define DEV_ADR  0x42

typedef struct Reg
{
	uint8_t Address;
	uint8_t Value;
}Reg_Info;


Reg_Info Sensor_Config[] =
{
	{REG_CLKRC,     0x00},
	{REG_COM7,      0x40},
	{REG_HSTART,    0x3f},
	{REG_HSIZE,     0x50},
	{REG_VSTRT,     0x03},
	{REG_VSIZE,     0x78},
	{REG_HREF,      0x00},
	{REG_HOutSize,  0x50},
	{REG_VOutSize,  0x78},
	{REG_EXHCH,     0x00},


	/*DSP control*/
	{REG_TGT_B,     0x7f},
	{REG_FixGain,   0x09},
	{REG_AWB_Ctrl0, 0xe0},
	{REG_DSP_Ctrl1, 0xff},
	{REG_DSP_Ctrl2, 0x20},
	{REG_DSP_Ctrl3,	0x00},
	{REG_DSP_Ctrl4, 0x00},

	/*AGC AEC AWB*/
	{REG_COM8,		0xf0},
	{REG_COM4,		0x81},
	{REG_COM6,		0xc5},
	{REG_COM9,		0x21},
	{REG_BDBase,	0xFF},
	{REG_BDMStep,	0x01},
	{REG_AEW,		0x34},
	{REG_AEB,		0x3c},
	{REG_VPT,		0xa1},
	{REG_EXHCL,		0x00},
	{REG_AWBCtrl3,  0xaa},
	{REG_COM8,		0xff},
	{REG_AWBCtrl1,  0x5d},

	{REG_EDGE1,		0x0a},
	{REG_DNSOff,	0x01},
	{REG_EDGE2,		0x01},
	{REG_EDGE3,		0x01},

	{REG_MTX1,		0x5f},
	{REG_MTX2,		0x53},
	{REG_MTX3,		0x11},
	{REG_MTX4,		0x1a},
	{REG_MTX5,		0x3d},
	{REG_MTX6,		0x5a},
	{REG_MTX_Ctrl,  0x1e},

	{REG_BRIGHT,	0x00},
	{REG_CNST,		0x25},
	{REG_USAT,		0x65},
	{REG_VSAT,		0x65},
	{REG_UVADJ0,	0x81},
	{REG_SDE,		  0x06},

	{REG_GAM1,		0x0c},
	{REG_GAM2,		0x16},
	{REG_GAM3,		0x2a},
	{REG_GAM4,		0x4e},
	{REG_GAM5,		0x61},
	{REG_GAM6,		0x6f},
	{REG_GAM7,		0x7b},
	{REG_GAM8,		0x86},
	{REG_GAM9,		0x8e},
	{REG_GAM10,		0x97},
	{REG_GAM11,		0xa4},
	{REG_GAM12,		0xaf},
	{REG_GAM13,		0xc5},
	{REG_GAM14,		0xd7},
	{REG_GAM15,		0xe8},
	{REG_SLOP,		0x20},

	{REG_HUECOS,	0x80},
	{REG_HUESIN,	0x80},
	{REG_DSPAuto,	0xff},
	{REG_DM_LNL,	0x00},
	{REG_BDBase,	0x99},
	{REG_BDMStep,	0x03},
	{REG_LC_RADI,	0x00},
	{REG_LC_COEF,	0x13},
	{REG_LC_XC,		0x08},
	{REG_LC_COEFB,  0x14},
	{REG_LC_COEFR,  0x17},
	{REG_LC_CTR,	0x05},

	{REG_COM3,		0xd0},


	{REG_COM5,		0xf5},
	//{REG_COM5,		0x31},
};

uint8_t OV7725_REG_NUM = sizeof(Sensor_Config)/sizeof(Sensor_Config[0]);


static void sccb_wait(void)
{
   uint16_t i = 400;
   while(i)
   {
     i--;
   }
}

void sccb_start(void)
{

  SCCB_SDA_OUT;

  SCCB_SDA_HIGH;
  //sccb_wait();
  SCCB_SCL_HIGH;
  sccb_wait();
  SCCB_SDA_LOW;
  sccb_wait();
  SCCB_SCL_LOW;
}


void sccb_stop(void)
{
  SCCB_SDA_OUT;

  SCCB_SDA_LOW;
  sccb_wait();
  SCCB_SCL_HIGH;
  sccb_wait();
  SCCB_SDA_HIGH;
  sccb_wait();
}


u8 sccb_sendByte(u8 data)
{
  u8 i;
   u8 ack;
  SCCB_SDA_OUT;
  for( i=0; i<8; i++)
  {
    if(data & 0x80)
      SCCB_SDA_HIGH;
    else
      SCCB_SDA_LOW;
    data <<= 1;
    sccb_wait();
    SCCB_SCL_HIGH;
    sccb_wait();
    SCCB_SCL_LOW;
    sccb_wait();
  }
  SCCB_SDA_HIGH;
  SCCB_SDA_IN;
  sccb_wait();
  SCCB_SCL_HIGH;
  sccb_wait();
  ack = SCCB_SDA_DATA;
  SCCB_SCL_LOW;
  sccb_wait();
  return ack;
}

u8 sccb_receiveByte(void)
{
  u8 i = 8;
  uint8_t ReceiveByte=0;

  sccb_wait();
  SCCB_SDA_OUT;
  sccb_wait();
  SCCB_SDA_HIGH;

  SCCB_SDA_IN;
  while(i--)
  {
    ReceiveByte<<=1;
    SCCB_SCL_LOW;
    sccb_wait();
    SCCB_SCL_HIGH;
    sccb_wait();
    if(SCCB_SDA_DATA)
    {
      ReceiveByte|=0x01;
    }
  }
  SCCB_SCL_LOW;

  SCCB_SDA_OUT;
  return ReceiveByte;
}


static void SCCB_NoAck(void)
{
	SCCB_SDA_OUT;
	SCCB_SCL_LOW;
	sccb_wait();
	SCCB_SDA_HIGH;
	sccb_wait();
	SCCB_SCL_HIGH;
	sccb_wait();
	SCCB_SCL_LOW;
	sccb_wait();

}

static void SCCB_Ack(void)
{
	SCCB_SDA_OUT;
	SCCB_SCL_LOW;
	sccb_wait();
	SCCB_SDA_LOW;
	sccb_wait();
	SCCB_SCL_HIGH;
	sccb_wait();
	SCCB_SCL_LOW;
	sccb_wait();

}


u8 sccb_regRead(u8 *pBuffer,u8 address,u8 length)
{
  u8 i;
  u8 ack;
  for( i=0; i<200; i++)
  {
    sccb_start();
    ack = sccb_sendByte(0x42);
    if( ack == 1 )
    {
      sccb_stop();
      continue;
    }

    ack = sccb_sendByte(address);
    if( ack == 1 )
    {
      sccb_stop();
      continue;
    }

    sccb_stop();
    sccb_wait();
    sccb_start();
    ack = sccb_sendByte(0x42 + 1);
    if( ack == 1 )
    {
      sccb_stop();
      continue;
    }

    while(length)
    {
      *pBuffer = sccb_receiveByte();
      if(length == 1)
	  {
    	  SCCB_NoAck();
	  }
      else
	  {
		SCCB_Ack();
	  }
      pBuffer++;
      length--;
    }

    sccb_stop();
    if( ack == 0 ) break;
  }
  return ack;
}


u8 sccb_regWrite(u8 device,u8 address,u8 data)
{
  u8 i;
  u8 ack;
  for( i=0; i<200; i++)
  {
    sccb_start();
    ack = sccb_sendByte(device);
    if( ack == 1 )
    {
      sccb_stop();
      continue;
    }

    ack = sccb_sendByte(address);
    if( ack == 1 )
    {
      sccb_stop();
      continue;
    }

    ack = sccb_sendByte(data);
    if( ack == 1 )
    {
      sccb_stop();
      continue;
    }

    sccb_stop();
    if( ack == 0 ) break;
  }
  return ack;
}

void OV7725_Window_Set(uint16_t sx,uint16_t sy,uint16_t width,uint16_t height)
{
	uint8_t reg_raw,cal_temp;

	sccb_regRead(&reg_raw,REG_HSTART,1);
	cal_temp = (reg_raw + (sx>>2));
	sccb_regWrite(0x42,REG_HSTART,cal_temp);

	sccb_regWrite(0x42,REG_HSIZE,width>>2);

	sccb_regRead(&reg_raw,REG_VSTRT,1);
	cal_temp = (reg_raw + (sy>>1));
	sccb_regWrite(0x42,REG_VSTRT,cal_temp);

	sccb_regWrite(0x42,REG_VSIZE,height>>1);

	sccb_regRead(&reg_raw,REG_HREF,1);
	cal_temp = (reg_raw |(width&0x03)|((height&0x01)<<2)|((sx&0x03)<<4)|((sy&0x01)<<6));
	sccb_regWrite(0x42,REG_HREF,cal_temp);


	sccb_regWrite(0x42,REG_HOutSize,width>>2);
	sccb_regWrite(0x42,REG_VOutSize,height>>1);

	sccb_regRead(&reg_raw,REG_EXHCH,1);
	cal_temp = (reg_raw |(width&0x03)|((height&0x01)<<2));

	sccb_regWrite(0x42,REG_EXHCH,cal_temp);
}



unsigned char OV7725_Init(void)
{
    u8 i =0;
    u8 id;
    while( 1 == sccb_regWrite ( 0x42, 0x12, 0x80 ) )
    {
        i++;
	    if(i == 20)
	    {
		 return 0 ;
		}
    }
    sccb_regRead(&id,0x0b,1) ;
	if(id == OV7725_ID)
	{
		for( i = 0 ; i < OV7725_REG_NUM ; i++ )
		{
			if( 1 == sccb_regWrite(0x42,Sensor_Config[i].Address, Sensor_Config[i].Value) )
			{

				return 0;
			}
		}
		OV7725_Window_Set(79,39,160,160);

	}


    return 1;
}

void R_FIFO_Create(void)
{
	WE = 1U;              	//disable write
	OE = 0U;		//disable read
}


void FIFO_PREPARE(void)
{
	RRST = 0U;
	RCK = 0U;
	RCK = 1U;
	RRST = 1U;
	RCK = 0U;
	RCK = 1U;
}


#define IMAGE_SEND_EN  0



void ReadOnePic(void)
{
	unsigned int i,j;
    uint8_t camera,flag1 =0,flag2 =0;

   if(Ov7725_vsync==2)
   {

	 FIFO_PREPARE();
#if  IMAGE_SEND_EN
	 R_SCI1_Serial_Send_Char(0x01);
	 R_SCI1_Serial_Send_Char(0xfe);
#endif

     for(i=0;i<160;i++)
     {
    	 for(j=0;j<160;j++)
    	 {
    		 RCK=0;
    		 camera = PORT4.PIDR.BYTE;
    	     RCK=1;
    	     RCK=0;
    	     RCK=1;

    	    if(flag1 == 0 && flag2 == 0)
    	    {
    	    	if(camera > Image_thr)
    	    	{
    	    		Image_Bin[i >> 1][j >> 1] = 255;

    	    	}
    	    	else
    	    		Image_Bin[i >> 1][j >> 1] =0;
    	       //Image_Bin[i >> 1][j >> 1] = camera;
#if  IMAGE_SEND_EN
    	    	R_SCI1_Serial_Send_Char(camera);
#endif
    	    }
    	    flag1 = !flag1;
         }
    	 flag2 = !flag2;
     }

#if  IMAGE_SEND_EN
     R_SCI1_Serial_Send_Char(0xfe);
     R_SCI1_Serial_Send_Char(0x01);
#endif
	  Ov7725_vsync = 0;
	  ImagRecOK = 1;
   }
}




